/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package src.parseInfo;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.html.DomAttr;
import com.gargoylesoftware.htmlunit.html.DomText;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.LogFactory;
import org.apache.xerces.util.URI.MalformedURIException;
import src.pojo.Catagory;
import src.pojo.Product;

/**
 *
 * @author LeMinh
 */
public class SimpleParser implements WebParser {

    private WebParseInfor infor;
    private WebClient webClient;

    public SimpleParser() {
        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log",
                "org.apache.commons.logging.impl.NoOpLog");
        webClient = new WebClient(BrowserVersion.FIREFOX_17);
        webClient.getOptions().setThrowExceptionOnScriptError(false);
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        webClient.getOptions().setCssEnabled(false);//if you don't need css
        webClient.getOptions().setJavaScriptEnabled(false);//if you don't need js
        webClient.setJavaScriptTimeout(30000); //e.g. 30s
    }

    public void setInfor(WebParseInfor infor) {
        this.infor = infor;
    }

    public void setWebClient(WebClient webClient) {
        this.webClient = webClient;
    }

    @Override
    public List<Catagory> getCatagories() {
        try {
            List<Catagory> catagories = new ArrayList<Catagory>();
            WebRequest webRequest = new WebRequest(new URL(infor.getParsePage()));
            webRequest.setCharset("utf-8");
            HtmlPage page = (HtmlPage) webClient.getPage(webRequest);
            List<HtmlElement> menuLinks = (List<HtmlElement>) page.getByXPath(infor.getMenuLinksXpath());
            for (HtmlElement menuLink : menuLinks) {
                String catagoryName = menuLink.getTextContent();
                String catagoryLink = menuLink.getAttribute("href");
                Catagory catagory = new Catagory(catagoryName, catagoryLink, infor.getWebPage());
                catagories.add(catagory);
            }
            System.out.println(catagories.size() + " is found.");
            return catagories;
        } catch (IOException ex) {
            Logger.getLogger(SimpleParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FailingHttpStatusCodeException ex) {
            Logger.getLogger(SimpleParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    @Override
    public List<Product> getProducts() {
        List<Catagory> catagories = new ArrayList<Catagory>();
        List<Product> listProduct = new ArrayList<Product>();
        for (Catagory cata : catagories) {
            listProduct.addAll(getProductByCatagories(cata));
        }
        return listProduct;
    }

    @Override
    public List<Product> getProduct(int... catagoryIndexs) {
        List<Catagory> catagories = getCatagories();
        List<Product> listProduct = new ArrayList<Product>();
        for (int i = 0; i < catagoryIndexs.length; i++) {
            int catagoryIndex = catagoryIndexs[i];
            if (catagoryIndex < catagories.size()) {
                listProduct.addAll(getProductByCatagories(catagories.get(catagoryIndex)));
            } else {
                System.out.println(catagoryIndex + " out of array");
            }
        }
        return listProduct;
    }

    @Override
    public List<Product> getProductByCatagories(Catagory inCatagory) {
        List<Product> products = new ArrayList<Product>();
        System.out.println("Get Products of catagory: " + inCatagory.getCatagoryName());
        String[] type = inCatagory.getCatagoryName().split(" |\\,");
        String t = type[0] + " " + type[1];
        t = t.toLowerCase();
        List<String> links = new ArrayList<String>();
        links.add(inCatagory.getCatagoryLink());
        links.addAll(getPagingUrls(inCatagory));

        try {
            for (String st : links) {

                WebRequest webRequest = new WebRequest(new URL(st));
                webRequest.setCharset("utf-8");
                System.out.println("get of links: " + st);
                HtmlPage catagoryPage = webClient.getPage(st);
                //lay toan bo cac san pham
                List<HtmlElement> singleProductDivs = (List<HtmlElement>) catagoryPage.getByXPath(infor.getProductsXpath());
                for (HtmlElement productDiv : singleProductDivs) {
                    DomAttr linkAttr = productDiv.getFirstByXPath(infor.getLinkXpath());
                    DomAttr imgAttr = productDiv.getFirstByXPath(infor.getImgXpath());
                    DomText nameText = productDiv.getFirstByXPath(infor.getNameXpath());
                    DomText PriceText = productDiv.getFirstByXPath(infor.getPriceXpath());
                    try {
                        String productLink = linkAttr.getValue();
                        // System.out.println(productLink);
                        String imgLink = imgAttr.getValue();
                        // System.out.println(imgLink);
                        String name = nameText.asText();
                        // System.out.println(name);
                        String price = PriceText.asText();
                        // System.out.println(price);
                        Product pro = new Product(t, name, price, imgLink, productLink, infor.getWebPage());
                        products.add(pro);
                    } catch (NullPointerException e) {
                        try {
                            String productLink = linkAttr.getValue();
                            String imgLink = imgAttr.getValue();
                            String name = nameText.asText();
                            String price = PriceText.asText();
                            Product pro = new Product(t, name, price, imgLink, productLink, infor.getWebPage());
                            products.add(pro);
                        } catch (NullPointerException ex) {
                            System.out.println("Parse error by" + ex.getCause());
                            System.out.println(productDiv.asXml());
                        }
                    }
                }
            }
            return products;
        } catch (IOException ex) {
            Logger.getLogger(SimpleParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FailingHttpStatusCodeException ex) {
            Logger.getLogger(SimpleParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

    }

    @Override
    public void setWebParseInfo(WebParseInfor parseInfo) {
        this.infor = parseInfo;
    }

    @Override
    public List<String> getPagingUrls(Catagory cata) {
        List<String> pagingUrls = new ArrayList<String>();
        try {

            HtmlPage page = webClient.getPage(cata.getCatagoryLink());
            List<DomAttr> pagingUrl = (List<DomAttr>) page.getByXPath(infor.getPagingLinksXpath());
            if (!pagingUrl.isEmpty()) {
                for (DomAttr url : pagingUrl) {
                    System.out.println(url.getValue());
                    String link = "";
                    if (!url.getValue().contains("http")) {
                        link = infor.getWebPage() + url.getValue();
                    } else {
                        link = url.getValue();
                    }
                    pagingUrls.add(link);
                }
                System.out.println("Paging " + pagingUrls.size() + " is found.");
                return pagingUrls;
            }
        } catch (IOException ex) {
            Logger.getLogger(SimpleParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FailingHttpStatusCodeException ex) {
            Logger.getLogger(SimpleParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
}
